#include"file.h"
#include"syscall.h"
#include"os_modules.h"
#include"stdio.h"
#include"asm_utils.h"

const int MAX_FILES=100;
File fileTable[MAX_FILES];
bool fileStatus[MAX_FILES];//文件状态
openFile openFiles[MAX_FILES];//打开文件

FileSystem::FileSystem()
{
    initialize();
}
void FileSystem::initialize()
{
    for(int i=0;i<MAX_FILES;i++)
    {
        fileTable[i]=File();
        fileTable[i].id=i;
        fileStatus[i]=false;
        openFiles[i]=openFile();
    }
    root=allocateFile();
    strcpy(root->name,"root");
    strcpy(root->location,"root/");
    current=root;
}
File* FileSystem::allocateFile()
{
    for(int i=0;i<MAX_FILES;i++)
    {
        if(!fileStatus[i])
        {
            fileStatus[i]=true;
            fileTable[i].fileData.content=(char*)malloc(sizeof(char)*1024);
            fileTable[i].fileData.contentSize=1024;
            return &fileTable[i];
        }
    }
    return nullptr;
}
void FileSystem::release(File* file)
{
    int index=file->id;
    if(!fileStatus[index])return;
    //文件打开则释放失败
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(file->name,openFiles[index].name)==0)
        {
            printf("This file %s is open,can't release!\n",file->name);
            return;
        }
    }
    fileStatus[index]=false;
    fileTable[index]=File();
    fileTable[index].id=index;
    if(fileTable[index].fileData.contentSize>0)free(fileTable[index].fileData.content);
    for(int i=0;i<10;i++)
    {
        if(strcmp(current->directoryData.children[i]->name,file->name)==0)
        {
            index=i;
            break;
        }
    }
    for(int i=index;i<current->directoryData.childCount-index-1;i++)
    {
        current->directoryData.children[i]=current->directoryData.children[i+1];
    }
    current->directoryData.children[current->directoryData.childCount-1]=nullptr;
    current->directoryData.childCount--;
}
File* FileSystem::createFile(const char* name,fileType type)
{
    if(strlen(name)>16)
    {
        printf("file name can't > 16!\n");
        return nullptr;
    }
    if(current->directoryData.childCount>=10)
    {
        printf("This file already has 10 files,failed.\n");
        return nullptr;
    }
    File* file=allocateFile();

    file->type=type;
    strcpy(file->name,name);
    strcpy(file->location,current->location);
    appendStr(file->location,file->name);
    appendStr(file->location,"/");
    //将文件加入当前目录，同时文件的第一个子目录是上级目录
    current->directoryData.children[(current->directoryData.childCount)++]=file;
    file->directoryData.children[(file->directoryData.childCount)++]=current;
}
void FileSystem::deleteFile(const char* name)
{
    if(name=="root")
    {
        printf("root file can't delete.\n");
        return;
    }
    //文件打开则释放失败
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(name,openFiles[i].name)==0)
        {
            printf("This file %s is open,can't delete!\n",name);
            return;
        }
    }
    //找到file
    File* file=nullptr;
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(name,fileTable[i].name)==0)
        {
            file=&fileTable[i];
            break;
        }
    }
    if(file->directoryData.childCount>1)
    {
        for(int i=1;i<file->directoryData.childCount;i++)
        {
            deleteFile(file->directoryData.children[i]->name);
        }
    }
    release(file);
}
void FileSystem::open(const char* name)
{
    //找到file
    File* file=nullptr;
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(name,fileTable[i].name)==0)
        {
            file=&fileTable[i];
            break;
        }
    }
    if(file==nullptr)
    {
        printf("This file %s not exist.\n",name);
        return;
    }
    //打开文件
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(fileTable[i].name,"")==0)
        {
            openFiles[i]=openFile(file->id,file->name,1);
            return;
        }
    }
    printf("open files full.\n");
}
void FileSystem::close(const char* name)
{
    //找到file
    File* file=nullptr;
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(name,fileTable[i].name)==0)
        {
            file=&fileTable[i];
            break;
        }
    }
    if(file==nullptr)
    {
        printf("This file %s not exist.\n",name);
        return;
    }
    //打开文件
    for(int i=0;i<MAX_FILES;i++)
    {
        if(strcmp(fileTable[i].name,file->name)==0)
        {
            openFiles[i]=openFile();
            return;
        }
    }
    printf("close failed.\n");
}
int FileSystem::read(const char* name,char* buffer,int size)
{
    //找到file
    File* file=nullptr;
    for(int i=0;i<current->directoryData.childCount;i++)
    {
        if(strcmp(current->directoryData.children[i]->name,name)==0)
        {
            file=current->directoryData.children[i];   
            break;
        }
    }
    if(file==nullptr)
    {
        printf("This file %s not exist.\n",name);
        return 0;
    }
    if(file->fileData.contentSize==0)
    {
        printf("read failed.\n");
        return 0;
    }else if(file->fileData.contentSize<size){
        size=file->fileData.contentSize;
        printf("There just %d size.\n",size);
    }
    memcpy(file->fileData.content,buffer,size);
    return size;
}
int FileSystem::write(const char* name,int position,const char* data,int size)
{
    //找到file
    File* file=nullptr;
    for(int i=0;i<current->directoryData.childCount;i++)
    {
        if(strcmp(current->directoryData.children[i]->name,name)==0)
        {
            file=current->directoryData.children[i];   
            break;
        }
    }
    if(file==nullptr)
    {
        printf("This file %s not exist.\n",name);
        return 0;
    }
    if(position>=file->fileData.contentSize)
    {
        printf("position too big.\n");
        return 0;
    }else if(position+size>file->fileData.contentSize){
        printf("position+size too big.\n");
        return 0;
    }
    memcpy((char*)data,file->fileData.content+position,size);
    return size;
}
void FileSystem::cd(const char* name)
{
    //找到file
    for(int i=0;i<current->directoryData.childCount;i++)
    {
        if(strcmp(current->directoryData.children[i]->name,name)==0)
        {
            current=current->directoryData.children[i];     
            return;
        }
    }
    printf("cd failed.\n");
}
void FileSystem::ls()
{
    //找到file
    printf("list directoy:%d\n",current->directoryData.childCount);
    File* file=nullptr;
    for(int i=0;i<current->directoryData.childCount;i++)
    {
        if(i==0 && strcmp(current->name,"root")!=0)printf("..:");
        printf("%s  ",current->directoryData.children[i]->name);
    }
    printf("\n");
}
void FileSystem::cat()
{
    for(int i=0;i<current->fileData.contentSize;i++)
    {
        printf("%c",current->fileData.content[i]);
    }
    printf("\n");
}
void FileSystem::pwd()
{
    printf("%s\n",current->location);
}
void FileSystem::echo(const char* data)
{
    printf("%s\n",data);
}

